package com.ysq.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ysq.controller.exception.CustomException;
import com.ysq.entity.Category;
import com.ysq.entity.Setmeal;
import com.ysq.entity.SetmealDish;
import com.ysq.entity.dto.SetmealDto;
import com.ysq.mapper.CategoryMapper;
import com.ysq.mapper.SetmealDishMapper;
import com.ysq.mapper.SetmealMapper;
import com.ysq.service.SetmealService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * ClassName: SetmealServiceImpl
 * Package: com.ysq.service.impl
 * Description:
 *
 * @Author YSQ
 * @Create 2023/1/3 - 12:58
 */
@Service
public class SetmealServiceImpl implements SetmealService {
    @Autowired
    private SetmealMapper mapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private CategoryMapper categoryMapper;

    @Override
    @Transactional //涉及到多表操作, 添加事务
    public boolean saveWithDish(SetmealDto setmealDto) {
        //保存套餐信息到套餐表setmeal
        int row = mapper.insert(setmealDto);
        //setmealDto中有套餐菜品信息 套餐菜品对应这个套餐
        //所以我们要获取这个套餐的ID
        Long setmealId = setmealDto.getId();
        //获取菜品信息
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        //遍历集合, 给里面的菜品设置对应的套餐ID且保存到套餐菜品表setmeal_dish
        for (SetmealDish setmealDish : setmealDishes) {
            setmealDish.setSetmealId(setmealId);//设置套餐ID
            row += setmealDishMapper.insert(setmealDish);
        }
        return row > 0;
    }

    @Override
    public Page<SetmealDto> selectPage(int page, int pageSize, String name) {
        //构造分页构造器 ==> 创建page分页对象, 设置分页参数
        Page<Setmeal> setmealPage = new Page<>(page, pageSize);//这是setmeal对应的page
        Page<SetmealDto> setmealDtoPage = new Page<>(page, pageSize);//这是setmealDto对应的page
        //设置查询条件
        LambdaQueryWrapper<Setmeal> lqw = new LambdaQueryWrapper<>();
        lqw.like(name != null, Setmeal::getName, name);//模糊查询
        lqw.orderByDesc(Setmeal::getUpdateTime);//根据更新时间倒序排序
        //执行查询
        mapper.selectPage(setmealPage, lqw);//查询完了之后 setmealPage 中就已经包含了分页相关的全部数据

        //现在setmealPage里什么都有, 我们要把它们都拷贝到dishDtoPage
        //但是records要单独处理, 所以暂时不拷贝过去, records里面放的就是查询到的dish表里的数据
        BeanUtils.copyProperties(setmealPage, setmealDtoPage, "records");
        //为什么要单独处理? 因为setmealPage里面的records里面放的是setmeal, setmeal里面有categoryId
        //我们要根据categoryId查询category表找到对应的name存放到setmealDtoPage的records的categoryName属性里
        //上面的话读3遍

        //现在SetmealDtoPage里面除了records数据, 别的都有了, 我们现在就要把它的records数据搞出来
        //先来一个空的list
        List<SetmealDto> list = new ArrayList<>();
        //注意下方操作, 都是为了把 List<DishDto> list 填满
        //1. 获取setmealPage的records数据
        List<Setmeal> records = setmealPage.getRecords();
        //2. 遍历records, records里面放的都是查询出来的一个个Setmeal对象
        for (Setmeal setmeal : records) {
            //3. 创建SetmealDto对象 将record数据拷贝给setmealDto
            SetmealDto setmealDto = new SetmealDto();
            BeanUtils.copyProperties(setmeal, setmealDto);
            //4. 得到这个套餐对应的分类ID
            Long categoryId = setmeal.getCategoryId();
            //5. 根据分类ID查询category表找到name字段, 也就是这个套餐对应的套餐分类的名字
            //记得注入CategoryMapper 因为要查询category表
            Category category = categoryMapper.selectById(categoryId);
            //6. 获得这个对应套餐分类的名字
            String categoryName = category.getName();
            //7. 把这个名字赋给setmealDto的categoryName属性
            setmealDto.setCategoryName(categoryName);
            //8. 把这个setmealDto对象加到集合list里
            list.add(setmealDto);
        }
        //最后把这个集合给到setmealDtoPage的records属性, 大功告成!
        setmealDtoPage.setRecords(list);

        //把setmealDtoPage返回
        return setmealDtoPage;
    }

    @Override
    public SetmealDto selectWithDish(Long id) {
        //1. 根据套餐ID查询到套餐数据
        Setmeal setmeal = mapper.selectById(id);
        //2. 将setmeal的内容拷贝到setmealDto
        SetmealDto setmealDto = new SetmealDto();
        BeanUtils.copyProperties(setmeal, setmealDto);
        //3. 根据ID在套餐菜品表setmeal_dish中查询到这道菜品对应的套餐 封装为List集合
        LambdaQueryWrapper<SetmealDish> lqwSetmealDish = new LambdaQueryWrapper<>();
        lqwSetmealDish.eq(SetmealDish::getSetmealId, id);
        List<SetmealDish> setmealDishes = setmealDishMapper.selectList(lqwSetmealDish);
        //4. 将查询到的口味集合赋给setmealDto
        setmealDto.setSetmealDishes(setmealDishes);
        //5. 返回setmealDto
        return setmealDto;
    }

    @Override
    @Transactional //涉及到多表操作, 添加事务
    public boolean editSetmeal(SetmealDto setmealDto) {
        //捋一捋思路, 这里要操作2个表: 更新setmeal表 在setmeal_dish表中删除旧菜品, 插入新菜品
        //1. 更新setmeal表
        int row = mapper.updateById(setmealDto);//DishDto继承Dish, 而且此时dishDto里面也有ID属性, 前端传来封装好了

        //2. 在setmeal_dish表中删除旧菜品
        //2.1 获取套餐ID
        Long setmealId = setmealDto.getId();
        //2.2 构造条件构造器
        LambdaQueryWrapper<SetmealDish> lqwSetmealDish = new LambdaQueryWrapper<>();
        //2.3 插入条件
        lqwSetmealDish.eq(SetmealDish::getSetmealId, setmealId);
        //2.4 根据条件删除旧菜品
        row += setmealDishMapper.delete(lqwSetmealDish);

        //3. 在setmeal_dish表中插入新菜品
        //3.1 获取套餐新菜品信息
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        //3.2 遍历集合, 给里面的新菜品对象设置对应的套餐ID且保存到套餐菜品表
        for (SetmealDish setmealDish : setmealDishes) {
            setmealDish.setSetmealId(setmealId);//设置对应的套餐ID
            row += setmealDishMapper.insert(setmealDish);//保存新菜品到setmeal_dish表
        }

        return row > 0;
    }

    @Override
    public boolean updateSale(int status, Long[] ids) {
        int row = 0;
        for (Long id : ids) {
            //根据ID查询到这个套餐
            Setmeal setmeal = mapper.selectById(id);
            //在dish表中更新这个套餐的状态
            setmeal.setStatus(status);
            row = mapper.updateById(setmeal);
        }
        return row > 0;
    }

    @Override
    @Transactional //多表操作, 添加事务
    public boolean delete(List<Long> ids) {
        //这里要对两个表进行操作, 一个是setmeal套餐表, 一个是setmean_dish套餐菜品表
        //删除套餐的时候, setmeal套餐表里对应的套餐数据要删除, setmean_dish套餐菜品表这个套餐对应的菜品也要删除

        //那么我们先来进行第一步: 删除setmeal套餐表里对应的套餐
        //这里也是有条件要判断的: 如果状态是启售也就是status属性为1, 那么是不能删的, 只有状态是禁售才能删除
        //我们要执行的语句应该是 select count(*) from setmeal where id in (?, ?, ?) and status = 1;
        //如果查到的结果>0 那么代表setmeal表里有满足这些条件的套餐, 且状态是启售, 那么绝对不能删, 抛出业务异常
        //具体操作如下:
        //1. 构造条件构造器
        LambdaQueryWrapper<Setmeal> lqwSetmeal = new LambdaQueryWrapper<>();
        //2. 插入条件
        lqwSetmeal.eq(Setmeal::getStatus, 1);//where status = 1
        lqwSetmeal.in(Setmeal::getId, ids);//where id in (?, ?, ?)
        //3. 执行查询
        Long count = mapper.selectCount(lqwSetmeal);
        //4. 判断是否删除
        if (count > 0) {
            //套餐状态为启售, 不能删, 抛出业务异常
            throw new CustomException("套餐正在售卖, 请先停售再进行删除~~~");
        }
        //执行到这里, 代表套餐状态是禁售, 可以删除
        int row = mapper.deleteBatchIds(ids);//批量删除, 要传入集合

        //能够执行到这里, 代表套餐表setmeal中的套餐已经删除了, 接下来就要删除setmean_dish套餐菜品表这些套餐对应的菜品
        //我们拿到的是套餐id, 我们要根据套餐id来进行条件删除
        //说白了就是执行 delete * from setmeal_dish where setmeal_id in (?, ?, ?);
        //那么来呗, 具体操作如下:
        //1. 构造条件构造器
        LambdaQueryWrapper<SetmealDish> lqwSetmealDish = new LambdaQueryWrapper<>();
        //2. 插入条件
        lqwSetmealDish.in(SetmealDish::getSetmealId, ids);//where setmeal_id in (?, ?, ?)
        //3. 执行删除
        row += setmealDishMapper.delete(lqwSetmealDish);

        return row > 0;
    }

    @Override
    public List<Setmeal> list(Setmeal setmeal) {
        //条件构造器
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        //添加条件
        queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, 1);
        //排序
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
        //查询
        List<Setmeal> setmeals = mapper.selectList(queryWrapper);
        //将结果返回
        return setmeals;
    }
}
